///////////////////////////////////////////////////////////////////////////////
// File:        PlayerManager.cc
// Author:      671643387@qq.com
// Description: 
///////////////////////////////////////////////////////////////////////////////

#include <errno.h>
#include <boost/bind.hpp>
#include "Log.hpp"
#include "player/PlayerManager.hpp"
using namespace boost::asio;

///////////////////////////////////////////////////////////////////////////////

#define PLAYER_MAP_INIT_SIZE    0x1000

///////////////////////////////////////////////////////////////////////////////

PlayerManager::PlayerManager(void)
    : iosev_()
    , acceptor_(iosev_)
    
    , playerIDGen_(0)
    , players_(PLAYER_MAP_INIT_SIZE)
    , playerLock_()
{

}

PlayerManager::~PlayerManager(void)
{

}

///////////////////////////////////////////////////////////////////////////////

bool PlayerManager::open(std::string address, short port, int backlog)
{
    try
    {
        ip::tcp::endpoint endpt(ip::address::from_string(address), port);
        acceptor_.open(endpt.protocol());
        acceptor_.set_option(ip::tcp::acceptor::reuse_address(true));
        acceptor_.bind(endpt);
        acceptor_.listen(backlog);
        return _postAccept();
    }
    catch (boost::system::error_code /*e*/)
    {
        return false;
    }
}

int PlayerManager::run(void)
{
    boost::system::error_code err;
    iosev_.run(err);
    return err.value();
}

void PlayerManager::stop(void)
{
    {
        boost::lock_guard<boost::mutex> guard(playerLock_);
        PlayerMap::iterator iter = players_.begin();
        PlayerMap::iterator mapend = players_.end();
        for (; iter != mapend; ++iter)
            iter->second->_close();
        players_.clear();
    }

    iosev_.stop();
}

///////////////////////////////////////////////////////////////////////////////

void PlayerManager::closePlayer(int id)
{
    boost::lock_guard<boost::mutex> guard(playerLock_);
    PlayerMap::iterator iter = players_.find(id);
    if (iter != players_.end())
        players_.erase(iter);
}

///////////////////////////////////////////////////////////////////////////////

PlayerPtr PlayerManager::createPlayer(void)
{
    return PlayerPtr(new Player());
}

///////////////////////////////////////////////////////////////////////////////

bool PlayerManager::_postAccept(void)
{
    socket_ptr sock(new boost::asio::ip::tcp::socket(iosev_));
    if (!sock) return false;
    acceptor_.async_accept(*sock, 
        boost::bind(&PlayerManager::_onAccept, this, sock, _1));
    return true;
}

///////////////////////////////////////////////////////////////////////////////

void PlayerManager::_onAccept(socket_ptr sock, const boost::system::error_code& err)
{
    do 
    {
        if (err)
        {
            ERROR_LOG("%d, accept new connection\n", err);
            break;
        }

        PlayerPtr player = createPlayer();
        if (!player)
        {
            ERROR_LOG("%d, create player\n", errno);
            break;
        }

        player->_init(++playerIDGen_, sock, this);

        {
            boost::lock_guard<boost::mutex> guard(playerLock_);
            players_[player->GetID()] = player;
        }

        player->postRecv();

    } while (false);

    if (!_postAccept())
    {
        ERROR_LOG("%d, post accept\n", errno);
    }
}